<?php
namespace App\Http\Middleware\TokenMiddleware;

use App\Exception\TokenException;
use App\Helper\JwtHelper;
use App\Http\Lib\Service;
use App\Http\Lib\ServiceInfo;
use App\Rpc\Model\Dao\UserCarrierDao;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Token;
use phpDocumentor\Reflection\Types\Context;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\BeanFactory;
use Swoft\Console\Router\Module;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Message\Request;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Contract\MiddlewareInterface;
use Swoft\Redis\Redis;

/**
 * Token校验
 * Class ValidateToken
 * @package App\Http\Middleware\TokenMiddleware
 * @Bean(name="ValidateToken")
 */
class ValidateToken implements  MiddlewareInterface
{

    /**
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     * @throws \App\Exception\TokenException
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // 如果开启了JWT校验则进行JWT token 校验
        if (!constant(Module::DEFINE_DISABLE_JWT_MODULE)) {
            // 获取上级中间件中传递的服务信息
            /** @var Service $service */
            $service = $request->getAttribute('service');
            /** @var ServiceInfo $serviceInfo */
            $serviceInfo = $request->getAttribute('serviceInfo');

            // 判断 请求的 action 是否需要校验
            if(need_valid($serviceInfo->getServiceName(), $serviceInfo->getServer(), $serviceInfo->getAction())){
                // 获取用户参数
                $requestData = $request->input();
                // 需要校验
                try {
                    // 首先校验 token 参数格式
                    validate($requestData, "TokenValidator", ['token']);
                    /** @var JwtHelper $JwtHelper */
                    $JwtHelper = BeanFactory::getBean('JwtHelper');
                    // 转化token 为 对象
                    $token = (new Parser())->parse((string)$requestData['token']);
                } catch (\Exception $e) {
                    // 转化过程除了问题 报错
                    throw new TokenException("非法 Token", 460 );
                }
                /** @var Token $token */
                if ($token->verify( $JwtHelper->getSigner(), $JwtHelper->getKey() ) ) {
                    //这里如果是选择用户被禁用或者什么的就需要进行token删除
                    $uid = $token->getClaim("uid");
                    $type = $token->getClaim('type');
                    $unionId = $token->getClaim('unionId');
                    /** @var UserCarrierDao $dao */
                    $dao = get_user_dao(intval($type));
                    $userInfo = $dao->getByWhere([
                        'item_id' => $uid
                    ]);

                    if(!$userInfo || ($userInfo['frozenState']??2) <> 0){
                        //账号状态不合法请重新登录,删除token
                        /** @var JwtHelper $JwtHelper */
                        $JwtHelper = BeanFactory::getBean('JwtHelper');
                        $JwtHelper->delToken($uid);
                        throw new TokenException('账号状态不合法请重新登录', 460);
                    }

                    // 验证通过了 进行下一步
                    // 通过新增uid
                    return $handler->handle($request
                        ->withAttribute('uid', $uid)
                        ->withAttribute('type', $type)
                        ->withAttribute('unionId', $unionId)
                    );
                }
                // token 错误
                throw new TokenException("Token 验证错误", 460 );
            }
        }

        // 如果不需要校验 直接到下一步
        return $handler->handle($request);
    }
}
